---
id: event-handling
title: 事件处理
sidebar_label: 事件处理
---

# 事件处理

OpenInula 提供了简单直观的事件处理机制，使用 `onXxx` 属性来绑定事件处理函数。

## 基本用法

### 点击事件

最常用的事件处理是点击事件：

```tsx filename="ClickCounter.jsx"
function ClickCounter() {
  let count = 0;
  
  function handleClick() {
    count++;
  }
  
  return (
    <button onClick={handleClick}>
      点击次数：{count}
    </button>
  );
}
```

### 内联事件处理

对于简单的事件处理，可以直接使用内联函数：

```tsx filename="SimpleButton.jsx"
function SimpleButton() {
  let message = '';
  
  return (
    <div>
      <button onClick={() => message = '你好！'}>
        打招呼
      </button>
      <p>{message}</p>
    </div>
  );
}
```

## 常用事件

### 表单事件

处理表单输入和提交：

```tsx filename="LoginForm.jsx"
function LoginForm() {
  let username = '';
  let password = '';
  
  function handleSubmit(e) {
    e.preventDefault();
    console.log('提交登录:', { username, password });
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={username}
        onInput={e => username = e.target.value}
        placeholder="用户名"
      />
      <input
        type="password"
        value={password}
        onInput={e => password = e.target.value}
        placeholder="密码"
      />
      <button type="submit">登录</button>
    </form>
  );
}
```

### 鼠标事件

处理鼠标相关事件：

```tsx filename="MouseTracker.jsx"
function MouseTracker() {
  let position = { x: 0, y: 0 };
  
  return (
    <div
      onMouseMove={e => {
        position = {
          x: e.clientX,
          y: e.clientY
        };
      }}
      style={{ height: '200px', background: '#f0f0f0' }}
    >
      <p>鼠标位置：{position.x}, {position.y}</p>
    </div>
  );
}
```

### 键盘事件

处理键盘输入：

```tsx filename="KeyboardInput.jsx"
function KeyboardInput() {
  let pressedKeys = [];
  
  return (
    <input
      onKeyDown={e => {
        pressedKeys = [...pressedKeys, e.key];
      }}
      onKeyUp={e => {
        pressedKeys = pressedKeys.filter(key => key !== e.key);
      }}
      placeholder="请按键..."
    />
  );
}
```

## 事件修饰符

OpenInula 支持事件修饰符来简化常见的事件处理场景：

```tsx filename="EventModifiers.jsx"
function EventModifiers() {
  return (
    <div>
      {/* 阻止默认行为 */}
      <a onClick={e => e.preventDefault()} href="#">
        阻止默认跳转
      </a>
      
      {/* 停止事件传播 */}
      <div onClick={() => console.log('外层点击')}>
        <button 
          onClick={e => {
            e.stopPropagation();
            console.log('按钮点击');
          }}
        >
          点击我
        </button>
      </div>
    </div>
  );
}
```

## 自定义事件

在组件间通信时，可以通过 props 传递自定义事件处理函数：

```tsx filename="CustomButton.jsx"
function CustomButton({ onClick, children }) {
  return (
    <button
      onClick={e => {
        // 可以在这里添加自定义逻辑
        console.log('按钮被点击');
        onClick?.(e);
      }}
    >
      {children}
    </button>
  );
}

function App() {
  return (
    <CustomButton onClick={() => console.log('处理点击')}>
      点击我
    </CustomButton>
  );
}
```

## 最佳实践

### 1. 事件处理函数命名

建议使用 `handle` 前缀命名事件处理函数：

```tsx filename="UserForm.jsx"
function UserForm() {
  let formData = {
    name: '',
    email: ''
  };
  
  function handleNameChange(e) {
    formData.name = e.target.value;
  }
  
  function handleEmailChange(e) {
    formData.email = e.target.value;
  }
  
  function handleSubmit(e) {
    e.preventDefault();
    console.log('提交表单:', formData);
  }
  
  return (
    <form onSubmit={handleSubmit}>
      <input
        value={formData.name}
        onChange={handleNameChange}
      />
      <input
        value={formData.email}
        onChange={handleEmailChange}
      />
      <button type="submit">提交</button>
    </form>
  );
}
```

### 2. 事件参数处理

在需要传递额外参数时，使用箭头函数包装：

```tsx filename="ItemList.jsx"
function ItemList() {
  const items = ['项目1', '项目2', '项目3'];
  
  function handleItemClick(item, index, e) {
    console.log('点击项目:', item, '索引:', index, '事件:', e);
  }
  
  return (
    <ul>
      <for each={items}>
        {(item, index) => (
          <li onClick={(e) => handleItemClick(item, index, e)}>
            {item}
          </li>
        )}
      </for>
    </ul>
  );
}
```

### 3. 性能优化

对于频繁触发的事件，考虑使用节流或防抖：

```tsx filename="SearchInput.jsx"
function SearchInput() {
  let searchTerm = '';
  let timeoutId;
  
  function handleInput(e) {
    // 使用防抖处理搜索
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => {
      searchTerm = e.target.value;
      console.log('搜索:', searchTerm);
    }, 300);
  }
  
  willUnmount(() => {
    clearTimeout(timeoutId);
  });
  
  return (
    <input
      type="text"
      onInput={handleInput}
      placeholder="搜索..."
    />
  );
}
```

## 注意事项

1. 事件处理函数中的 `this` 绑定
2. 避免在渲染函数中创建内联函数
3. 记得清理定时器和事件监听器
4. 注意事件冒泡和捕获的顺序

## 下一步

学习完事件处理后，你可以：

1. 探索[组件组合](../../components/composition)的技巧
2. 了解[生命周期](../../lifecycle/mounting)的管理
3. 学习[状态管理](../../reactivity/state)的最佳实践